/**
 * Copyright (c) 2007-2012, JGraph Ltd
 */
package com.neuronbit.businessflow.intellij.editor.swing.editor;

import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.swing.util.mxGraphTransferable;
import com.mxgraph.swing.util.mxSwingConstants;
import com.mxgraph.util.*;
import com.mxgraph.util.mxEventSource.mxIEventListener;

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

/**
 * The type Editor palette.
 */
public class EditorPalette extends JPanel {
    private static final long serialVersionUID = 7771113885935187066L;
    /**
     * The Selected entry.
     */
    protected JLabel selectedEntry = null;
    /**
     * The Event source.
     */
    protected mxEventSource eventSource = new mxEventSource(this);

    /**
     * Instantiates a new Editor palette.
     */
    @SuppressWarnings("serial")
    public EditorPalette() {
        //setBackground(new Color(149, 230, 190));
        setLayout(new FlowLayout(FlowLayout.LEADING, 5, 5));

        // Clears the current selection when the background is clicked
        addMouseListener(new MouseListener() {

            /*
             * (non-Javadoc)
             * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
             */
            public void mousePressed(MouseEvent e) {
                clearSelection();
            }

            /*
             * (non-Javadoc)
             * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
             */
            public void mouseClicked(MouseEvent e) {
            }

            /*
             * (non-Javadoc)
             * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
             */
            public void mouseEntered(MouseEvent e) {
            }

            /*
             * (non-Javadoc)
             * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
             */
            public void mouseExited(MouseEvent e) {
            }

            /*
             * (non-Javadoc)
             * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
             */
            public void mouseReleased(MouseEvent e) {
            }

        });

        // Shows a nice icon for drag and drop but doesn't import anything
        setTransferHandler(new TransferHandler() {
            public boolean canImport(JComponent comp, DataFlavor[] flavors) {
                return true;
            }
        });
    }

    /**
     * Clear selection.
     */
    public void clearSelection() {
        setSelectionEntry(null, null);
    }

    /**
     * Sets selection entry.
     *
     * @param entry the entry
     * @param t     the t
     */
    public void setSelectionEntry(JLabel entry, mxGraphTransferable t) {
        JLabel previous = selectedEntry;
        selectedEntry = entry;

        if (previous != null) {
            previous.setBorder(null);
            previous.setOpaque(false);
        }

        if (selectedEntry != null) {
            selectedEntry.setBorder(ShadowBorder.getSharedInstance());
            selectedEntry.setOpaque(true);
        }

        eventSource.fireEvent(new mxEventObject(mxEvent.SELECT, "entry",
                selectedEntry, "transferable", t, "previous", previous));
    }

    /**
     * Sets preferred width.
     *
     * @param width the width
     */
    public void setPreferredWidth(int width) {
        int cols = Math.max(1, width / 55);
        setPreferredSize(new Dimension(width, (getComponentCount() * 55 / cols) + 30));
        revalidate();
    }

    /**
     * Add edge template.
     *
     * @param name   the name
     * @param icon   the icon
     * @param style  the style
     * @param width  the width
     * @param height the height
     * @param value  the value
     */
    public void addEdgeTemplate(final String name, ImageIcon icon, String style, int width, int height, Object value) {
        mxGeometry geometry = new mxGeometry(0, 0, width, height);
        geometry.setTerminalPoint(new mxPoint(0, height), true);
        geometry.setTerminalPoint(new mxPoint(width, 0), false);
        geometry.setRelative(true);

        mxCell cell = new mxCell(value, geometry, style);
        cell.setEdge(true);

        addTemplate(name, icon, cell);
    }

    /**
     * Add template.
     *
     * @param name   the name
     * @param icon   the icon
     * @param style  the style
     * @param width  the width
     * @param height the height
     * @param value  the value
     */
    public void addTemplate(final String name, ImageIcon icon, String style,
                            int width, int height, Object value) {
        mxCell cell = new mxCell(value, new mxGeometry(0, 0, width, height), style);
        cell.setVertex(true);

        addTemplate(name, icon, cell);
    }

    /**
     * Add template.
     *
     * @param name the name
     * @param icon the icon
     * @param cell the cell
     */
    public void addTemplate(final String name, ImageIcon icon, mxCell cell) {
        mxRectangle bounds = (mxGeometry) cell.getGeometry().clone();
        final mxGraphTransferable t = new mxGraphTransferable(new Object[]{cell}, bounds);

        // Scales the image if it's too large for the library
        if (icon != null) {
            if (icon.getIconWidth() > 32 || icon.getIconHeight() > 32) {
                icon = new ImageIcon(icon.getImage().getScaledInstance(32, 32, 0));
            }
        }

        final JLabel entry = new JLabel(icon);
        entry.setPreferredSize(new Dimension(50, 50));
        //entry.setBackground(EditorPalette.this.getBackground().brighter());
        entry.setFont(new Font(entry.getFont().getFamily(), 0, 10));

        entry.setVerticalTextPosition(JLabel.BOTTOM);
        entry.setHorizontalTextPosition(JLabel.CENTER);
        entry.setIconTextGap(0);

        entry.setToolTipText(name);
        entry.setText(name);

        Color color= UIUtil.getLabelTextForeground();

        //Set JLabel text color to color that you choose
        entry.setForeground(color);

        entry.addMouseListener(new MouseListener() {

            /*
             * (non-Javadoc)
             * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
             */
            public void mousePressed(MouseEvent e) {
                setSelectionEntry(entry, t);
            }

            /*
             * (non-Javadoc)
             * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
             */
            public void mouseClicked(MouseEvent e) {
            }

            /*
             * (non-Javadoc)
             * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
             */
            public void mouseEntered(MouseEvent e) {
            }

            /*
             * (non-Javadoc)
             * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
             */
            public void mouseExited(MouseEvent e) {
            }

            /*
             * (non-Javadoc)
             * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
             */
            public void mouseReleased(MouseEvent e) {
            }

        });

        // Install the handler for dragging nodes into a graph
        DragGestureListener dragGestureListener = new DragGestureListener() {
            /**
             *
             */
            public void dragGestureRecognized(DragGestureEvent e) {
                e.startDrag(null, mxSwingConstants.EMPTY_IMAGE, new Point(), t, null);
            }

        };

        DragSource dragSource = new DragSource();
        dragSource.createDefaultDragGestureRecognizer(entry, DnDConstants.ACTION_COPY, dragGestureListener);

        add(entry);
    }

    /**
     * Add listener.
     *
     * @param eventName the event name
     * @param listener  the listener
     * @see mxEventSource#addListener(String, mxIEventListener) mxEventSource#addListener(String, mxIEventListener)mxEventSource#addListener(String, mxIEventListener)
     */
    public void addListener(String eventName, mxIEventListener listener) {
        eventSource.addListener(eventName, listener);
    }

    /**
     * Is events enabled boolean.
     *
     * @return whether or not event are enabled for this palette
     * @see mxEventSource#isEventsEnabled() mxEventSource#isEventsEnabled()mxEventSource#isEventsEnabled()
     */
    public boolean isEventsEnabled() {
        return eventSource.isEventsEnabled();
    }

    /**
     * Remove listener.
     *
     * @param listener the listener
     * @see mxEventSource#removeListener(mxIEventListener) mxEventSource#removeListener(mxIEventListener)mxEventSource#removeListener(mxIEventListener)
     */
    public void removeListener(mxIEventListener listener) {
        eventSource.removeListener(listener);
    }

    /**
     * Remove listener.
     *
     * @param listener  the listener
     * @param eventName the event name
     * @see mxEventSource#removeListener(String, mxIEventListener) mxEventSource#removeListener(String, mxIEventListener)mxEventSource#removeListener(String, mxIEventListener)
     */
    public void removeListener(mxIEventListener listener, String eventName) {
        eventSource.removeListener(listener, eventName);
    }

    /**
     * Sets events enabled.
     *
     * @param eventsEnabled the events enabled
     * @see mxEventSource#setEventsEnabled(boolean) mxEventSource#setEventsEnabled(boolean)mxEventSource#setEventsEnabled(boolean)
     */
    public void setEventsEnabled(boolean eventsEnabled) {
        eventSource.setEventsEnabled(eventsEnabled);
    }

}
